home *** CD-ROM | disk | FTP | other *** search
- /*==============================================================================
- Project: POV
-
- Version: 3
-
- File: MemAlloc.c
-
- Description:
- Routines to handle the Mac-specific memory handling, by rerouting the POV_MALLOC
- style calls through to the appropriate routines.
- ------------------------------------------------------------------------------
- Author:
- Eduard [esp] Schwan
- ------------------------------------------------------------------------------
- from Persistence of Vision(tm) Ray Tracer
- Copyright 1996 Persistence of Vision Team
- ------------------------------------------------------------------------------
- NOTICE: This source code file is provided so that users may experiment
- with enhancements to POV-Ray and to port the software to platforms other
- than those supported by the POV-Ray Team. There are strict rules under
- which you are permitted to use this file. The rules are in the file
- named POVLEGAL.DOC which should be distributed with this file. If
- POVLEGAL.DOC is not available or for more info please contact the POV-Ray
- Team Coordinator by leaving a message in CompuServe's Graphics Developer's
- Forum. The latest version of POV-Ray may be found there as well.
-
- This program is based on the popular DKB raytracer version 2.12.
- DKBTrace was originally written by David K. Buck.
- DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
- ------------------------------------------------------------------------------
- Change History:
- ==============================================================================*/
-
- #define MEMALLOC_C
-
- #include "MemAlloc.h"
- #include "Stdio_p2w.h" // printf
-
- #include "USERIO.H" // Error
-
- #include <types.h>
- #include <stdlib.h> // malloc
- #include <string.h> // strcpy, memset
- #include <memory.h> // NewPtr
- #include <errors.h> // memFullErr
- #include <ToolUtils.h> // watchCursor
-
-
- // =====================================================================
- // Configuration flags, change these to alter how memory is allocated.
- // NOTE: After extensive testing, here's what I've found:
- // With USE_NATIVE_MALLOC off (0), POV-Ray runs the fastest, but there's
- // a catch. Most implementations of malloc/free seem to leave Mac
- // memory allocated, even though it is freed via free(). And although
- // the next render will re-use this space, two things happen... (1) because
- // this free-pool memory is not released, regular Mac memory cannot use the
- // space, so after the first render, you have permanently lost some heap
- // space, which could have been used by the offscreen image, etc. and
- // (2) each time you render, a little extra free-pool space is used for some
- // reason (fragmentation?), meaning that during batch or animation renders,
- // you could eventually run out of memory. [esp]
- // =====================================================================
-
- // turn this off to use C's malloc(), on for Mac's NewPtr()/NewHandle()
- // #define USE_NATIVE_MALLOC 1
-
- #if (USE_NATIVE_MALLOC)
- // Use Mac's NewHandle() instead of NewPtr()
- // (only makes sense if USE_NATIVE_MALLOC is ON)
- #define USE_MEM_HANDLES 1
- #endif
-
-
-
- // =====================================================================
- // undefine our earlier re-definitions of the stdlib calls,
- // so we can call them ourselves here.
- #undef malloc
- #undef calloc
- #undef realloc
- #undef free
-
- // This defines the lowest free memory is allowed to get before
- // malloc & calloc fail. This guarantees some free heap space for
- // error recovery.
- #define MIN_SAFE_BYTES 100*1024L
-
-
- // Memory allocation tracking (Garbage Collection)
- static Handle gReserveBuffer = NULL;
-
- // Set to true to allocate temp memory (via UseTempMem(t/f) method)
- static Boolean gUseTempMem = false;
-
-
- // =====================================================================
- void UseTempMem(int doIt)
- {
- gUseTempMem = doIt;
- } // UseTempMem
-
- // =====================================================================
- void AllocateSafetyBuffer(size_t reserve_size)
- {
- // OSErr anError;
-
- if (gReserveBuffer == NULL)
- {
- gReserveBuffer = NewHandle(reserve_size);
- if (gReserveBuffer)
- {
- MoveHHi(gReserveBuffer);
- // mark it so Macsbug snoopers know what it is
- HLock(gReserveBuffer);
- strcpy(*gReserveBuffer, "Safety Buffer");
- HUnlock(gReserveBuffer);
- }
- }
- } // AllocateSafetyBuffer
-
-
- // =====================================================================
- void PurgeSafetyBuffer(void)
- {
- if (gReserveBuffer)
- {
- DisposeHandle(gReserveBuffer);
- gReserveBuffer = NULL;
- }
- } // PurgeSafetyBuffer
-
-
- // =====================================================================
- // Return true if we've had to purge our safety buffer
- Boolean InLowMemoryMode(void)
- {
- return gReserveBuffer == NULL;
- }
-
-
- // =====================================================================
- static void HandleOutOfMem(void)
- {
- // We are most likely out of memory. For now, we will free all the
- // allocated memory, and exit back to the main loop with an error.
- // We could be down to 5 or 10 bytes of available memory, and to do
- // anything else (like return from malloc and let the caller handle it)
- // risks a hard lockup or crash! So, first, make sure there's room
- // for loading dialogs & stuff in POV_reclaim(), by dumping the buffer memory.
- PurgeSafetyBuffer();
-
- // open some more heap space
- // [esp] this is commented out in 3.0.1 to see if we handle lomem conditions better without it
- // (void)CompactMem(FreeMem());
-
- // tell user we failed from here and exit out of all fn calls
- // this is a POV-Ray USERIO.C call.
- Error("Ran out of application memory; Increase POV-Ray application memory size.\n");
-
- // beep!
- SysBeep(2);
-
- } // HandleOutOfMem
-
-
- // =====================================================================
- void *Mac_malloc(size_t size)
- {
- void *myptr = NULL;
- #if USE_MEM_HANDLES
- Handle myhdl = NULL;
- #endif
- Boolean enoughMem;
-
- // free memory available?
- if (gUseTempMem)
- enoughMem = TempFreeMem() > MIN_SAFE_BYTES*2;
- else
- enoughMem = MaxBlock() > MIN_SAFE_BYTES;
-
- if (enoughMem)
- {
-
- #if USE_NATIVE_MALLOC
- #if USE_MEM_HANDLES
- OSErr anError;
- // use locked handles
- if (gUseTempMem)
- {
- myhdl = TempNewHandle(size, &anError);
- }
- else
- myhdl = NewHandle(size);
-
- if (myhdl)
- {
- if (gUseTempMem)
- HLock(myhdl);
- else
- HLockHi(myhdl); // move it up and lock it down
- anError = MemError();
-
- // it's really a handle, turn it into a pointer
- myptr = *myhdl;
- }
- #else
- // use regular pointers
- if (gUseTempMem)
- myptr = NewPtr(size);
- else
- myptr = NewPtr(size);
- #endif // USE_MEM_HANDLES
- #else
- // use Std C Lib allocator
- myptr = malloc(size);
- #endif // USE_NATIVE_MALLOC
- }
-
- // allocation was unsuccessful
- if (myptr == NULL)
- HandleOutOfMem();
-
- return myptr;
-
- } // Mac_malloc
-
-
- // =====================================================================
- void *Mac_calloc(size_t nmemb, size_t size)
- {
- void *myptr = NULL;
- #if USE_MEM_HANDLES
- Handle myhdl = NULL;
- #endif
- Boolean enoughMem;
-
- if (gUseTempMem)
- enoughMem = TempFreeMem() > MIN_SAFE_BYTES*2;
- else
- enoughMem = MaxBlock() > MIN_SAFE_BYTES;
-
- if (enoughMem)
- {
-
- #if USE_NATIVE_MALLOC
- #if USE_MEM_HANDLES
- // use locked handles
- if (gUseTempMem)
- {
- OSErr anError;
- myhdl = TempNewHandle(nmemb*size, &anError);
- }
- else
- myhdl = NewHandleClear(nmemb*size);
-
- if (myhdl)
- {
- if (gUseTempMem)
- {
- HLock(myhdl);
- memset(*myhdl, 0, nmemb*size);
- }
- else
- HLockHi(myhdl); // move it up and lock it down
- // it's really a handle, turn it into a pointer
- myptr = *myhdl;
- }
- #else
- // use regular pointers
- if (gUseTempMem)
- myptr = NewPtrClear(nmemb*size);
- else
- myptr = NewPtrClear(nmemb*size);
- #endif // USE_MEM_HANDLES
- #else
- myptr = calloc(nmemb,size);
- #endif // USE_NATIVE_MALLOC
-
- }
-
- // allocation was unsuccessful
- if (myptr == NULL)
- HandleOutOfMem();
-
- return myptr;
-
- } // Mac_calloc
-
-
-
- // =====================================================================
- void *Mac_realloc(void * p, size_t newsize)
- {
- #if USE_NATIVE_MALLOC
- size_t oldsize;
- #endif
- #if USE_MEM_HANDLES
- Handle myhdl = NULL;
- #endif
- Boolean enoughMem;
- void *myptr = NULL;
-
- // Warn user if nil pointer passed in!
- if (p == NULL)
- {
- printf("## Warning! Ignoring an attempt to realloc a nil pointer!\n");
- return NULL;
- }
-
- if (gUseTempMem)
- enoughMem = TempFreeMem() > MIN_SAFE_BYTES*2;
- else
- enoughMem = MaxBlock() > MIN_SAFE_BYTES;
-
- if (enoughMem)
- {
- #if USE_NATIVE_MALLOC
-
- #if USE_MEM_HANDLES
- // get previous size for shrink/grow check
- if (gUseTempMem)
- oldsize = GetHandleSize(RecoverHandle((Ptr)p));
- else
- oldsize = GetHandleSize(RecoverHandle((Ptr)p));
-
- // allocate new space... use locked handles
- if (gUseTempMem)
- {
- OSErr anError;
- myhdl = TempNewHandle(newsize, &anError);
- }
- else
- myhdl = NewHandle(newsize);
-
- // it's really a handle, turn it into a pointer
- if (myhdl)
- {
- if (gUseTempMem)
- HLock(myhdl);
- else
- HLockHi(myhdl); // move it up and lock it down
- myptr = *(Handle)myhdl; // initialize it for later
- }
- #else
- // get previous size for shrink/grow check
- oldsize = GetPtrSize(p);
- // allocate new space... use regular pointers
- if (gUseTempMem)
- myptr = NewPtr(newsize);
- else
- myptr = NewPtr(newsize);
- #endif // USE_MEM_HANDLES
-
- if (myptr)
- {
- // copy old contents into new space (trim if less space)
- BlockMoveData(p, myptr, (oldsize<newsize)?oldsize:newsize);
-
- // now release old memory...
- Mac_free(p);
- }
- #else
- // do the ANSI thing
- myptr = realloc(p, newsize);
- #endif // USE_NATIVE_MALLOC
- }
-
- // allocation was unsuccessful
- if (myptr == NULL)
- HandleOutOfMem();
-
- // let caller know the new pointer
- return myptr;
-
- } // Mac_realloc
-
-
- // =====================================================================
- void Mac_free(void *myptr)
- {
- #if USE_MEM_HANDLES
- Handle myhdl = NULL;
- #endif // USE_MEM_HANDLES
-
- if (myptr == NULL)
- {
- printf("## Warning! Ignoring an attempt to free a nil pointer!\n");
- }
- else
- {
- #if USE_NATIVE_MALLOC
- #if USE_MEM_HANDLES
- // use Mac locked handles
- // find it
- if (gUseTempMem)
- myhdl = RecoverHandle((Ptr)myptr);
- else
- myhdl = RecoverHandle((Ptr)myptr);
- // dump it
- if (myhdl)
- {
- DisposeHandle(myhdl);
- }
- else
- {
- printf("## Error %d! Cannot recover handle from ptr! ($%lx)\n",
- MemError(), myptr);
- }
- #else
- // use regular Mac pointers
- DisposePtr(myptr);
- #endif // USE_MEM_HANDLES
- #else
- // The Std C library way...
- free(myptr);
- #endif // USE_NATIVE_MALLOC
- }
- } // Mac_free
-
-